Conversation
추후 지용님 작업 내역과 merge 예정
WalkthroughAPI V2 엔드포인트가 도입되고 RecordFetchResult 도메인 모델로 반환 형태가 통합되었습니다. 감정(etс) 및 색상 팔레트 확장이 이루어졌고, 도서 상세 화면에 씨앗 기반 그래프·리포트 UI와 관련 데이터 흐름(mainEmotion) 연결이 추가되었습니다. Changes
Sequence Diagram(s)sequenceDiagram
participant View as BookDetailView
participant VC as BookDetailViewController
participant VM as BookDetailViewModel
participant UC as FetchRecordsUseCase
participant Repo as DefaultRecordRepository
participant API as RecordAPI
participant Resp as API Response
View->>VC: 초기 로드/스크롤 -> fetch page 0 액션 디스패치
VC->>VM: dispatch(.fetchRecords(page: 0))
VM->>UC: execute(id, page: 0)
UC->>Repo: fetch(bookId, sortType, page: 0)
Repo->>API: 요청 `.fetch` (uses APIConfig.baseV2URL)
API->>Resp: HTTP 응답 (V2 DTO)
Resp->>Repo: DTO → RecordFetchResult(mainEmotion 포함) 변환
Repo->>UC: RecordFetchResult 반환
UC->>VM: 성공 결과 전달(RecordFetchResult)
VM->>VC: 상태 발행(mainEmotion 포함)
VC->>View: applySeedHeader(mainEmotion) / SeedReportView.applyGraph(...)
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes 🚥 Pre-merge checks | ✅ 4 | ❌ 2❌ Failed checks (2 warnings)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing touches
🧪 Generate unit tests (beta)
⚔️ Resolve merge conflicts (beta)
No actionable comments were generated in the recent review. 🎉 🧹 Recent nitpick comments
Tip Issue Planner is now in beta. Read the docs and try it out! Share your feedback on Discord. Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 3
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (3)
src/Projects/BKPresentation/Sources/MainFlow/Note/View/EmotionRegistrationView.swift (1)
176-176:⚠️ Potential issue | 🟠 Major
hashValue를 view tag로 사용하는 것은 충돌 위험이 있습니다
hashValue는 Swift에서 고유성이 보장되지 않으며, 서로 다른 값이 동일한hashValue를 가질 수 있습니다. 이 경우emotionTapped에서 잘못된 감정이 선택될 수 있습니다.
Emotion이 이미CaseIterable을 준수하므로,Emotion.allCases.firstIndex(of:)를 사용하여 안정적인 정수 식별자를 얻을 수 있습니다:wrapperView.tag = Emotion.allCases.firstIndex(of: emotion) ?? 0그리고
emotionTapped에서:guard let tappedView = sender.view, let emotion = Emotion.allCases[safe: tappedView.tag] else { return }또는 더 간단하게:
let emotion = Emotion.allCases[tappedView.tag]src/Projects/BKDomain/Sources/Entity/Emotion.swift (1)
3-9:⚠️ Potential issue | 🟠 Major
etc케이스는 올바르게 추가되었으나 일부 switch 문에서 명시적 처리 필요합니다.
EmotionRegistrationView.swift라인 150과AppreciationResultView.swift라인 24의 switch 문이default케이스로.etc를 암묵적으로 처리하고 있습니다. 다음 파일들에서.etc케이스를 명시적으로 추가하세요:
EmotionRegistrationView.swift라인 150:case .etc를 추가하여 명시적으로 이미지를 지정AppreciationResultView.swift라인 24:case .etc를 추가하여 명시적으로 색상을 반환
EmotionSeed는 모든 computed property에서.etc를 올바르게 처리하고 있습니다 (baseColor에서는EmotionBase에.etc가 없으므로.bkEmotionColor(.etc)를 사용하는 것으로 의도적으로 구현됨).src/Projects/BKPresentation/Sources/MainFlow/BookDetail/Models/EmotionSeed.swift (1)
45-53:⚠️ Potential issue | 🟡 Minor
.etc의baseColor가 다른 케이스와 다른 패턴으로 처리되고 있습니다.다른 케이스들은
bkEmotionBaseColor()(연한 배경색)를 사용하지만,.etc는bkEmotionColor(.etc)(일반 텍스트 색상)를 사용합니다.EmotionBase에.etc케이스가 없어서 이렇게 처리한 것으로 보이나,baseColor가color와 동일한 값이 되어 시각적으로 배경색 역할을 하지 못할 수 있습니다.
🤖 Fix all issues with AI agents
In `@src/Projects/BKData/Sources/Constant/APIConfig.swift`:
- Around line 17-22: The fatalError message in the static property baseV2URL is
wrong — it reads "BKData.BASE_API_URL" while the code is loading the
"BASE_API_V2_URL" key; update the fatalError in the closure (the guard that
calls bundle.object(forInfoDictionaryKey:)) to reference the correct key name
("BASE_API_V2_URL") or include both key and module for clarity so the error
matches the attempted lookup in baseV2URL.
In `@src/Projects/BKData/Sources/DTO/Response/PrimaryEmotionResponseDTO.swift`:
- Around line 5-8: PrimaryEmotionResponseDTO currently decodes displayName
directly as the Emotion enum which will fail if the server string has different
casing/whitespace/locale or unknown values; change displayName in
PrimaryEmotionResponseDTO to decode as String (or implement a custom init(from:)
on PrimaryEmotionResponseDTO) and then map/convert that String to the Emotion
domain enum using a tolerant initializer on Emotion (e.g., trimming,
case-insensitive match, and a fallback case like .other or .unknown); update or
add an Emotion.init?(rawString: String) helper and use it inside
PrimaryEmotionResponseDTO's decoding logic so parsing never throws for
unexpected server values.
In
`@src/Projects/BKPresentation/Sources/MainFlow/BookDetail/View/SeedReportView.swift`:
- Around line 72-79: The configure() method currently sets a hardcoded
placeholder via reportLabel.setText(text: "테스트용 텍스트입니다.") which will be visible
if setEmotionHeader(with:) is never called (e.g., mainEmotion is nil); remove
the placeholder and instead handle the empty state by clearing the label or
hiding the whole view when no emotion is present: update configure() to not set
the test string, ensure setEmotionHeader(with:) populates reportLabel when
provided, and add logic (e.g., in setEmotionHeader(with:) or a new
updateEmptyState() helper) to call reportLabel.setText(text: "") or
self.isHidden = true when mainEmotion is nil so the placeholder is never shown.
🧹 Nitpick comments (11)
src/Projects/BKPresentation/Sources/MainFlow/Note/View/EmotionRegistrationView.swift (1)
26-27:default대신 명시적 케이스 매칭 고려새로운
.etc감정 케이스 추가로 인해default가 필요해진 것으로 보입니다. 하지만default를 사용하면 향후Emotion에 새로운 케이스가 추가될 때 컴파일러 경고 없이 자동으로warmEmotion으로 매핑되어 버그를 놓칠 수 있습니다.
default대신case .etc:(또는 현재 해당하는 케이스)를 명시적으로 매칭하면, 새 케이스 추가 시 컴파일 에러로 누락을 방지할 수 있습니다.제안
- default: + case .etc: imageView.image = BKImage.Graphics.warmEmotion두
switch문 모두 동일하게 적용하면 됩니다.Also applies to: 159-160
src/Projects/BKCore/Sources/Extension/Optional.swift (1)
3-3: 불필요한UIKitimport이 파일은
UIKit타입을 사용하지 않습니다.Foundation으로 충분합니다.♻️ 수정 제안
-import UIKit +import Foundationsrc/Projects/BKPresentation/Sources/MainFlow/NoteCompletion/View/AppreciationResultView.swift (1)
33-34:default대신.etc를 명시적으로 매칭하는 것을 고려해 주세요.현재
default는 향후Emotion에 새로운 케이스가 추가될 때 컴파일러 경고 없이.warmth로 매핑됩니다..etc를 명시적으로 처리하면 새 케이스 추가 시 컴파일 타임에 누락을 감지할 수 있습니다.♻️ 수정 제안
case .insight: return .insight - default: + case .etc: return .warmthsrc/Projects/BKDomain/Sources/Entity/RecordFetchResult.swift (1)
3-3:Foundationimport가 불필요해 보입니다.이 struct는
Foundation타입을 직접 사용하지 않습니다.RecordInfo와Emotion은 같은 모듈 내 타입이므로 import 없이도 접근 가능합니다.♻️ 제안
-import Foundationsrc/Projects/BKPresentation/Sources/MainFlow/BookDetail/View/SeedItemView.swift (1)
57-62:emotion이nil일 때 dot이 투명하게 표시됩니다.
EmotionSeed.from(seed:)가nil을 반환하면dotView.backgroundColor가nil(투명)이 됩니다.SeedGraphView에서는 같은 경우에.lightGray폴백을 사용하고 있어 동작이 일관되지 않습니다. 동일한 폴백 색상 적용을 고려해 주세요.♻️ 폴백 색상 추가 제안
- dotView.backgroundColor = emotion?.graphTintColor + dotView.backgroundColor = emotion?.graphTintColor ?? .lightGraysrc/Projects/BKPresentation/Sources/MainFlow/BookDetail/View/SeedGraphView.swift (1)
16-16:cornerRadius매직 넘버.
cornerRadius = 6이 하드코딩되어 있습니다.SeedItemView처럼BKRadius디자인 토큰 사용을 권장합니다.src/Projects/BKDesign/Sources/Foundation/ColorSystem/BKSemanticColor.swift (1)
142-142:Emotion.etc의 resolve 패턴이 다른 케이스들과 일관성이 없습니다.다른 케이스들은
BKAtomicColor.X.y.color처럼 정적 UIColor를 직접 반환하지만,.etc는bkContentColor(.secondary)를 사용하여traitCollection기반의 동적 UIColor를 반환합니다. 기능적으로는 동작하지만,resolve(for:)패턴에서 일관성이 깨집니다. 예를 들어, 다른 곳에서resolve(for: .light)의 결과가 정적 색상일 것이라 가정하고 비교하는 경우 예상치 못한 동작이 발생할 수 있습니다.♻️ 직접 atomic color를 반환하도록 변경 제안
- case .etc: return .bkContentColor(.secondary) + case .etc: return BKAtomicColor.Neutral.n500.colorsrc/Projects/BKPresentation/Sources/MainFlow/BookDetail/Models/EmotionSeed.swift (1)
21-21:.etc케이스의 이미지 리소스가 다른 감정의 것을 재사용하고 있습니다.
image는sad의 이미지,circleImage는insight의 원형 이미지,cardImage는sad의 카드 이미지를 사용하고 있습니다. 의도적인 임시 처리라면 괜찮지만, "기타" 감정에 슬픔이나 깨달음 관련 이미지가 보이면 사용자에게 혼동을 줄 수 있습니다. "기타"용 전용 이미지 에셋이 필요한지 디자인팀과 확인해 보시는 것을 권장합니다.Also applies to: 31-31, 97-97
src/Projects/BKPresentation/Sources/MainFlow/BookDetail/View/SeedReportView.swift (3)
124-129:labelsStackView높이에 매직 넘버72가 사용되고 있습니다.다른 레이아웃 값들은
LayoutConstants에 정의되어 있지만, 이 값만 인라인으로 하드코딩되어 있습니다. 일관성을 위해 상수로 추출하는 것을 권장합니다.♻️ LayoutConstants에 추가
enum LayoutConstants { // ... + static let labelsHeight: CGFloat = 72 static let graphHeight: CGFloat = 12 // ... }labelsStackView.snp.makeConstraints { $0.top.equalTo(graphView.snp.bottom).offset(LayoutConstants.labelsTopOffset) - $0.height.equalTo(72) + $0.height.equalTo(LayoutConstants.labelsHeight) $0.horizontalEdges.equalToSuperview() $0.bottom.equalToSuperview() }
132-139:emotion파라미터명이 로컬 변수에 의해 가려지고 있습니다(variable shadowing).Line 132의 파라미터
emotion: Emotion이 line 133의let emotion = EmotionSeed.from(emotion: emotion)에 의해 가려집니다. 동작에는 문제 없지만 가독성을 위해 로컬 변수명을 분리하는 것이 좋습니다.♻️ 변수명 분리 제안
func setEmotionHeader(with emotion: Emotion) { - let emotion = EmotionSeed.from(emotion: emotion) - let emotionText = "\'\(emotion.rawValue)\'" - emotionImageView.image = emotion.circleImage - reportLabel.highlightColor = emotion.color + let emotionSeed = EmotionSeed.from(emotion: emotion) + let emotionText = "\'\(emotionSeed.rawValue)\'" + emotionImageView.image = emotionSeed.circleImage + reportLabel.highlightColor = emotionSeed.color reportLabel.setText(text: "\(emotionText) 감정을 많이 느꼈어요") reportLabel.highlightedWord = emotionText }
163-177: 접기/펼치기 애니메이션 구현이 적절합니다.UIStackView의
isHidden애니메이션과 chevron 회전이 잘 결합되어 있습니다. 다만, 빠른 연속 탭 시 애니메이션 겹침이 발생할 수 있으므로, 필요하다면UIViewPropertyAnimator나 애니메이션 진행 중 탭 무시 등의 보호 로직을 추가할 수 있습니다.
src/Projects/BKData/Sources/DTO/Response/PrimaryEmotionResponseDTO.swift
Show resolved
Hide resolved
src/Projects/BKPresentation/Sources/MainFlow/BookDetail/View/SeedReportView.swift
Show resolved
Hide resolved
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Fix all issues with AI agents
In
`@src/Projects/BKPresentation/Sources/MainFlow/BookDetail/View/SeedReportView.swift`:
- Around line 61-69: The tap target for foldButton is too small (24x24) because
a UITapGestureRecognizer is added directly to the UIImageView in setupView;
increase the hit area to meet the 44x44pt HIG by replacing the UIImageView tap
approach with a larger tappable control or expanding its insets: make foldButton
a UIButton (or wrap the image in a UIButton), set appropriate contentEdgeInsets
to achieve at least 44x44 touchable area, attach the
UITapGestureRecognizer/action to toggleExpansion (or use UIButton.addTarget)
instead of directly on the image view, and ensure headerView layout constraints
for foldButton accommodate the larger hit frame.
🧹 Nitpick comments (2)
src/Projects/BKPresentation/Sources/MainFlow/BookDetail/View/SeedReportView.swift (2)
132-139:emotion파라미터명을 로컬 변수로 섀도잉하고 있습니다.Line 133에서
let emotion = EmotionSeed.from(emotion: emotion)으로 파라미터를 같은 이름으로 덮어쓰면 가독성이 떨어집니다.♻️ 리네이밍 제안
func setEmotionHeader(with emotion: Emotion) { - let emotion = EmotionSeed.from(emotion: emotion) - let emotionText = "\'\(emotion.rawValue)\'" - emotionImageView.image = emotion.circleImage - reportLabel.highlightColor = emotion.color - reportLabel.setText(text: "\(emotionText) \(emotion.descriptionText)") + let emotionSeed = EmotionSeed.from(emotion: emotion) + let emotionText = "\'\(emotionSeed.rawValue)\'" + emotionImageView.image = emotionSeed.circleImage + reportLabel.highlightColor = emotionSeed.color + reportLabel.setText(text: "\(emotionText) \(emotionSeed.descriptionText)") reportLabel.highlightedWord = emotionText }
163-176:private extension내의@objc private func에서private키워드가 중복됩니다.
private extension내 멤버는 이미private이므로 함수에 별도private지정이 불필요합니다.♻️ 중복 접근 제어자 제거
- `@objc` private func toggleExpansion() { + `@objc` func toggleExpansion() {
🔗 관련 이슈
📘 작업 유형
📙 작업 내역
🧪 테스트 내역
🎨 스크린샷 또는 시연 영상 (선택)
Simulator.Screen.Recording.-.ReedTest_26.2.-.2026-02-09.at.15.24.09.mp4
✅ PR 체크리스트
💬 추가 설명 or 리뷰 포인트 (선택)
Summary by CodeRabbit
새로운 기능
개선사항